using System;
using System.Collections.Generic;
using System.Text;

using PostSharp.Aspects;
using PostSharp;

namespace LoggingClient
{
    [Serializable]
    public class TraceAttribute : OnMethodBoundaryAspect
    {
        private const string MaskStr = "**Mask**";

        private bool mMaskArguments = false;

        public bool MaskArguments
        {
            get { return mMaskArguments; }
            set { mMaskArguments = value; }
        }

        public override void OnEntry(MethodExecutionArgs eventArgs)
        {
            try
            {
                StringBuilder MethodCall = new StringBuilder("");
                MethodCall.AppendFormat("-> {0} {1}", eventArgs.Method.DeclaringType, eventArgs.Method.Name);

                // Append Arguments
                MethodCall.AppendFormat(FormatArguments(eventArgs));

                TraceLogger.Instance.Debug(MethodCall.ToString());

                TraceLogger.Instance.Indent();
            }
            catch (Exception ex)
            {
                TraceLogger.Instance.Error(ex);
            }
        }

        public override void OnExit(MethodExecutionArgs eventArgs)
        {
            try
            {
                StringBuilder MethodCall = new StringBuilder("");
                MethodCall.AppendFormat("<- {0} {1} [{2}]", eventArgs.Method.DeclaringType, eventArgs.Method.Name, FormatReturnValue(eventArgs));

                TraceLogger.Instance.Debug(MethodCall.ToString());

                TraceLogger.Instance.Unindent();
            }
            catch (Exception ex)
            {
                TraceLogger.Instance.Error(ex);
            }
        }

        private string FormatReturnValue(MethodExecutionArgs eventArgs)
        {
            return (eventArgs.ReturnValue == null ? "Void/Null" : eventArgs.ReturnValue.ToString());
        }

        private string FormatArguments(MethodExecutionArgs eventArgs)
        {
            object[] argu = eventArgs.Arguments.ToArray();

            if (argu == null)
            {
                return "()";
            }
            else
            {
                string str = "(";

                for(int i=0; i<argu.Length; i++)
                {
                    if (!MaskArguments)
                    {
                        str += argu[i].ToString();
                    }
                    else
                    {
                        str += MaskStr;
                    }

                    if (i + 1 != argu.Length)
                    {
                        str += ", ";
                    }
                }

                str += ")";

                return str;
            }
        }
    }
}
